#pragma once

#include "kvector.h"
#include "klist.h"
#include "kdealloc.h"
#include "kstlbool.h"

#include <stdlib.h>

#ifdef TESTING
#include <stdio.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct KstlHashMap KstlHashMap;

typedef struct KstlHashMapIterator {
    KstlHashMap*       handle;
    KstlVectorIterator bucketIt;
    KstlListIterator   itemIt;
} KstlHashMapIterator;

typedef struct KstlHashMapSettings {
    size_t          itemSize;
    KstlDeallocator dealloc;
} KstlHashMapSettings;

#define KHM_FOR_EACH(handle, it, end)                                                                                  \
    for (KstlHashMapIterator(it) = KstlHashMapIteratorBegin((handle)), (end) = KstlHashMapIteratorEnd((handle));       \
         !KstlHashMapIteratorEqual((it), (end));                                                                       \
         KstlHashMapIteratorNext(&(it)))

KstlHashMap* KstlHashMapInit(KstlHashMapSettings settings);
void         KstlHashMapRelease(KstlHashMap* handle);


size_t KstlHashMapSize(KstlHashMap* handle);
size_t KstlHashMapRecycleCapacity(KstlHashMap* handle);
size_t KstlHashMapBucketCount(KstlHashMap* handle);

KstlHashMapIterator KstlHashMapAdd(KstlHashMap* handle, const void* key, const size_t keySize, const void* value);

int KstlHashMapGet(KstlHashMap* handle, const void* key, const size_t keySize, void* out);
int KstlHashMapErase(KstlHashMap* handle, const void* key, const size_t keySize);

KstlHashMapIterator KstlHashMapFind(KstlHashMap* handle, const void* key, const size_t keySize);

int KstlHashMapDelete(KstlHashMap* handle, KstlHashMapIterator it);

void KstlHashMapClear(KstlHashMap* handle);

KstlHashMapIterator KstlHashMapIteratorBegin(KstlHashMap* handle);
KstlHashMapIterator KstlHashMapIteratorEnd(KstlHashMap* handle);

void KstlHashMapIteratorNext(KstlHashMapIterator* it);
bool KstlHashMapIteratorEqual(KstlHashMapIterator current, KstlHashMapIterator end);

void*  KstlHashMapIteratorValue(KstlHashMapIterator current);
void*  KstlHashMapIteratorKey(KstlHashMapIterator current);
size_t KstlHashMapIteratorKeySize(KstlHashMapIterator current);

#ifdef __cplusplus
}  // extern "C"
#endif